package com.whfc.fuum.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.enums.NetState;
import com.whfc.common.enums.WorkState;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.PageUtil;
import com.whfc.fuum.dao.SysMachTypeIconMapper;
import com.whfc.fuum.dao.SysMachTypeMapper;
import com.whfc.fuum.dto.SysMachListDTO;
import com.whfc.fuum.dto.SysMachTypeDTO;
import com.whfc.fuum.dto.SysMachTypeIconDTO;
import com.whfc.fuum.entity.SysMachType;
import com.whfc.fuum.entity.SysMachTypeIcon;
import com.whfc.fuum.enums.MachTypeState;
import com.whfc.fuum.param.*;
import com.whfc.fuum.redis.MachTypeRedisDao;
import com.whfc.fuum.service.SysMachTypeService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClasssName SysMachTypeServiceImpl
 * @Description 设备类型实现类
 * @Author hw
 * @Date 2020/8/24 19:11
 * @Version 1.0
 */
@DubboService(interfaceClass = SysMachTypeService.class, version = "1.0.0")
public class SysMachTypeServiceImpl implements SysMachTypeService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    //private static final String MACH_TYPE_ICON_NAME = "https://file.whfciot.com/common/mach-icon/ty_%s.png";
    private static final String MACH_TYPE_ICON_NAME = "http://zhgd-file.oss-cn-hangzhou.aliyuncs.com/common/mach-icon/ty_%s.png";

    private static final String SHIP = "船";

    @Autowired
    private SysMachTypeMapper sysMachTypeMapper;

    @Autowired
    private SysMachTypeIconMapper sysMachTypeIconMapper;

    @Autowired
    private MachTypeRedisDao machTypeRedisDao;

    @Override
    public void machTypeClassifyAdd(SysMachTypeClassifyAddParam param) throws BizException {
        if (sysMachTypeMapper.selectByCode(param.getCode()) != null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "编码已存在");
        }
        SysMachType sysMachType = new SysMachType();
        BeanUtils.copyProperties(param, sysMachType);
        sysMachType.setPid(0);
        sysMachTypeMapper.insertSelective(sysMachType);
    }

    @Override
    public void machTypeClassifyEdit(SysMachTypeClassifyEditParam param) throws BizException {
        checkEdit(param.getCode(), param.getMachTypeId());
        SysMachType sysMachType = new SysMachType();
        BeanUtils.copyProperties(param, sysMachType);
        sysMachType.setId(param.getMachTypeId());
        sysMachTypeMapper.updateByPrimaryKeySelective(sysMachType);
    }

    @Override
    public void machTypeAdd(SysMachTypeAddParam param) throws BizException {
        SysMachType pSysMachType = sysMachTypeMapper.selectByCode(param.getCode());
        if (pSysMachType != null && !pSysMachType.getPid().equals(0)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "编码已存在");
        }
        pSysMachType = sysMachTypeMapper.selectByPrimaryKey(param.getPid());
        if (pSysMachType == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "父级id不存在");
        }
        SysMachType sysMachType = new SysMachType();
        BeanUtils.copyProperties(param, sysMachType);
        sysMachType.setCode(pSysMachType.getCode() + "." + param.getCode());
        sysMachTypeMapper.insertSelective(sysMachType);
        saveMachTypeIcon(sysMachType.getId(), param.getIcons(), sysMachType.getCode());
    }

    @Override
    public void machTypeEdit(SysMachTypeEditParam param) throws BizException {
        SysMachType pSysMachType = sysMachTypeMapper.selectByPrimaryKey(param.getPid());
        if (pSysMachType == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "父级id不存在");
        }
        param.setCode(pSysMachType.getCode() + "." + param.getCode());
        checkEdit(param.getCode(), param.getMachTypeId());
        SysMachType sysMachType = new SysMachType();
        BeanUtils.copyProperties(param, sysMachType);
        sysMachType.setId(param.getMachTypeId());
        sysMachTypeMapper.updateByPrimaryKeySelective(sysMachType);
        SysMachTypeDTO sysMachTypeDTO = to(sysMachType);
        machTypeRedisDao.delete(sysMachTypeDTO);
        //先把之前储存的图片删除后重新添加
        sysMachTypeIconMapper.deleteByMachTypeId(param.getMachTypeId());
        saveMachTypeIcon(sysMachType.getId(), param.getIcons(), sysMachType.getCode());
    }

    @Override
    public void machTypeDel(Integer machTypeId) throws BizException {
        List<SysMachTypeDTO> sysMachTypeDTOS = sysMachTypeMapper.selectByPid(machTypeId, null,null);
        if (sysMachTypeDTOS != null && sysMachTypeDTOS.size() > 0) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "已存在数据无法删除");
        }
        sysMachTypeIconMapper.deleteByMachTypeId(machTypeId);
        sysMachTypeMapper.deleteById(machTypeId);
    }

    @Override
    public void enable(Integer machTypeId, Integer state) throws BizException {
        sysMachTypeMapper.enable(machTypeId, state);
    }

    @Override
    public PageData<SysMachTypeDTO> machTypeList(Integer machTypeId, Integer pageNum, Integer pageSize, String keyword,Integer state) {
        if (machTypeId == null) {
            machTypeId = 0;
        }
        PageHelper.startPage(pageNum, pageSize);
        List<SysMachTypeDTO> sysMachTypeDTOList = sysMachTypeMapper.selectByPid(machTypeId, keyword,state);
        List<SysMachTypeIconDTO> sysMachTypeIconDTOList = sysMachTypeIconMapper.selectAll();
        sysMachTypeDTOList.forEach(sysMachTypeDTO -> {
            List<SysMachTypeIconDTO> icons = sysMachTypeIconDTOList.stream().filter(sysMachTypeIconDTO ->
                    sysMachTypeDTO.getMachTypeId().equals(sysMachTypeIconDTO.getMachTypeId())).collect(Collectors.toList());
            sysMachTypeDTO.setIcons(icons);
            sysMachTypeDTO.setCode(sysMachTypeDTO.getCode().substring(sysMachTypeDTO.getCode().lastIndexOf(".") + 1));
        });
        return PageUtil.pageData(PageInfo.of(sysMachTypeDTOList));
    }

    @Override
    public ListData<SysMachTypeDTO> machTypeList(String keyword) {
        return new ListData<>(sysMachTypeMapper.selectByPid(0, keyword,null));
    }

    @Override
    public ListData<SysMachListDTO> machLists(Integer machTypeId) throws BizException {
        List<SysMachListDTO> allMachTypes = sysMachTypeMapper.selectAll();

        if (CollectionUtils.isEmpty(allMachTypes)) {
            return new ListData<>(Collections.emptyList());
        }

        // 使用Map提高查找效率
        Map<Integer, SysMachListDTO> machTypeMap = new HashMap<>();
        Map<Integer, List<SysMachListDTO>> childrenMap = new HashMap<>();

        // 第一次遍历：建立映射关系
        for (SysMachListDTO item : allMachTypes) {
            machTypeMap.put(item.getMachTypeId(), item);

            // 构建父子关系映射
            if (!childrenMap.containsKey(item.getPid())) {
                childrenMap.put(item.getPid(), new ArrayList<>());
            }
            childrenMap.get(item.getPid()).add(item);
        }

        List<SysMachListDTO> retList = new ArrayList<>();

        if (machTypeId == null || machTypeId == 0) {
            // 查找所有根节点
            for (SysMachListDTO item : allMachTypes) {
                if (item.getPid() == 0) {
                    buildTree(item, childrenMap);
                    retList.add(item);
                }
            }
        } else {
            // 查找指定节点及其子树
            SysMachListDTO targetNode = machTypeMap.get(machTypeId);
            if (targetNode != null) {
                if (targetNode.getPid() == 0) {
                    // 如果是根节点，直接构建子树
                    buildTree(targetNode, childrenMap);
                    retList.add(targetNode);
                } else {
                    // 如果不是根节点，需要找到从根到该节点的完整路径
                    SysMachListDTO rootNode = findRootNode(targetNode, machTypeMap);
                    if (rootNode != null) {
                        buildTree(rootNode, childrenMap);
                        // 只返回包含目标节点的子树
                        retList.add(pruneTree(rootNode, machTypeId));
                    }
                }
            }
        }

        return new ListData<>(retList);
    }

    /**
     * 递归构建树形结构
     */
    private void buildTree(SysMachListDTO node, Map<Integer, List<SysMachListDTO>> childrenMap) {
        List<SysMachListDTO> children = childrenMap.get(node.getMachTypeId());
        if (children != null && !children.isEmpty()) {
            node.setChildren(children);
            for (SysMachListDTO child : children) {
                buildTree(child, childrenMap);
            }
        }
    }

    /**
     * 查找根节点
     */
    private SysMachListDTO findRootNode(SysMachListDTO node, Map<Integer, SysMachListDTO> machTypeMap) {
        if (node.getPid() == 0) {
            return node;
        }
        SysMachListDTO parent = machTypeMap.get(node.getPid());
        return parent != null ? findRootNode(parent, machTypeMap) : null;
    }

    /**
     * 修剪树，只保留包含目标节点的路径
     */
    private SysMachListDTO pruneTree(SysMachListDTO node, Integer targetMachTypeId) {
        if (node.getMachTypeId().equals(targetMachTypeId)) {
            return node;
        }

        if (node.getChildren() != null) {
            List<SysMachListDTO> prunedChildren = new ArrayList<>();
            for (SysMachListDTO child : node.getChildren()) {
                SysMachListDTO prunedChild = pruneTree(child, targetMachTypeId);
                if (prunedChild != null) {
                    prunedChildren.add(prunedChild);
                }
            }
            if (!prunedChildren.isEmpty()) {
                node.setChildren(prunedChildren);
                return node;
            }
        }

        return null;
    }

    @Override
    public String getIcon(String code, Integer netState) throws BizException {
        netState = NetState.OFFLINE.getValue().equals(netState) ? MachTypeState.GRAY.getValue() : MachTypeState.GREEN.getValue();
        SysMachTypeDTO sysMachTypeDTO = machTypeRedisDao.getMachType(code);
        String icon;
        if (sysMachTypeDTO == null) {
            sysMachTypeDTO = getSysMachType(code);
        }
        if (sysMachTypeDTO == null) {
            return String.format(MACH_TYPE_ICON_NAME, netState);
        }
        List<SysMachTypeIconDTO> icons = sysMachTypeDTO.getIcons();
        if (icons != null && icons.size() > netState) {
            icon = sysMachTypeDTO.getIcons().get(netState).getIcon();
            if (StringUtils.isNotEmpty(icon)) {
                return icon;
            }
        }
        return String.format(MACH_TYPE_ICON_NAME, netState);
    }

    @Override
    public String getIcon(String code, Integer netState, Integer workState) throws BizException {
        netState = NetState.OFFLINE.getValue().equals(netState) ? MachTypeState.GRAY.getValue() :
                WorkState.IDLE.getValue().equals(workState) ? MachTypeState.RED.getValue() :
                        WorkState.SLEEP.getValue().equals(workState)
                                || WorkState.STOP.getValue().equals(workState)
                                || WorkState.ERROR.getValue().equals(workState) ? MachTypeState.BLUE.getValue() :
                                MachTypeState.GREEN.getValue();
        SysMachTypeDTO sysMachTypeDTO = machTypeRedisDao.getMachType(code);
        String icon;
        if (sysMachTypeDTO == null) {
            sysMachTypeDTO = getSysMachType(code);
        }
        if (sysMachTypeDTO == null) {
            return String.format(MACH_TYPE_ICON_NAME, netState);
        }
        List<SysMachTypeIconDTO> icons = sysMachTypeDTO.getIcons();
        if (icons != null && icons.size() > netState) {
            icon = sysMachTypeDTO.getIcons().get(netState).getIcon();
            if (StringUtils.isNotEmpty(icon)) {
                return icon;
            }
        }
        return String.format(MACH_TYPE_ICON_NAME, netState);
    }

    @Override
    public String getIcon(Integer machTypeId, Integer netState, Integer workState) throws BizException {
        netState = NetState.OFFLINE.getValue().equals(netState) ? MachTypeState.GRAY.getValue() :
                WorkState.IDLE.getValue().equals(workState) ? MachTypeState.RED.getValue() :
                        WorkState.SLEEP.getValue().equals(workState)
                                || WorkState.STOP.getValue().equals(workState)
                                || WorkState.ERROR.getValue().equals(workState) ? MachTypeState.BLUE.getValue() :
                                MachTypeState.GREEN.getValue();
        SysMachTypeDTO sysMachTypeDTO = machTypeRedisDao.getMachType(machTypeId);
        String icon;
        if (sysMachTypeDTO == null) {
            sysMachTypeDTO = getSysMachType(machTypeId);
        }
        if (sysMachTypeDTO == null) {
            return String.format(MACH_TYPE_ICON_NAME, netState);
        }
        List<SysMachTypeIconDTO> icons = sysMachTypeDTO.getIcons();
        if (icons != null && icons.size() > netState) {
            icon = sysMachTypeDTO.getIcons().get(netState).getIcon();
            if (StringUtils.isNotEmpty(icon)) {
                return icon;
            }
        }
        return String.format(MACH_TYPE_ICON_NAME, netState);
    }


    @Override
    public String getIcon(Integer machTypeId, Integer type) throws BizException {
        SysMachTypeDTO sysMachTypeDTO = machTypeRedisDao.getMachType(machTypeId);
        String icon;
        if (sysMachTypeDTO == null) {
            sysMachTypeDTO = getSysMachType(machTypeId);
        }
        if (sysMachTypeDTO == null) {
            return String.format(MACH_TYPE_ICON_NAME, type);
        }
        List<SysMachTypeIconDTO> icons = sysMachTypeDTO.getIcons();
        if (icons != null && icons.size() > type) {
            icon = sysMachTypeDTO.getIcons().get(type).getIcon();
            if (StringUtils.isNotEmpty(icon)) {
                return icon;
            }
        }
        return String.format(MACH_TYPE_ICON_NAME, type);
    }


    @Override
    public String getMachTypeNameById(Integer machTypeId) throws BizException {
        SysMachTypeDTO machTypeDTO = machTypeRedisDao.getMachType(machTypeId);
        if (machTypeDTO == null) {
            machTypeDTO = getSysMachType(machTypeId);
        }
        return machTypeDTO != null ? machTypeDTO.getName() : "";
    }

    @Override
    public SysMachTypeDTO getMachTypeById(Integer machTypeId) throws BizException {
        SysMachTypeDTO machTypeDTO = machTypeRedisDao.getMachType(machTypeId);
        if (machTypeDTO == null) {
            machTypeDTO = getSysMachType(machTypeId);
        }
        return machTypeDTO;
    }


    @Override
    public String getParentMachTypeNameByCode(String code) throws BizException {
        SysMachTypeDTO machTypeDTO = machTypeRedisDao.getParentMachType(code);
        if (machTypeDTO == null) {
            machTypeDTO = getParentSysMachType(code);
        }
        return machTypeDTO != null ? machTypeDTO.getName() : "";
    }

    @Override
    public SysMachTypeDTO getParentMachTypeById(Integer machTypeId) throws BizException {
        SysMachTypeDTO machTypeDTO = machTypeRedisDao.getParentMachType(machTypeId);
        if (machTypeDTO == null) {
            machTypeDTO = getParentSysMachType(machTypeId);
        }
        return machTypeDTO;
    }


    @Override
    public boolean isShip(Integer machTypeId) throws BizException {
        SysMachType machType = sysMachTypeMapper.selectByPrimaryKey(machTypeId);
        SysMachTypeDTO parentType = sysMachTypeMapper.selectParentDTOById(machTypeId);
        if (machType != null && parentType != null) {
            if (machType.getName().contains(SHIP) || parentType.getName().contains(SHIP)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public SysMachTypeDTO getMachTypeByLikeMachName(String machName) throws BizException {
        if (machName == null) {
            return null;
        }
        return sysMachTypeMapper.selectByLikeMachName(machName);
    }

    private void checkEdit(String code, Integer machTypeId) {
        SysMachType sysMachType = sysMachTypeMapper.selectByCode(code);
        if (sysMachType != null && !sysMachType.getId().equals(machTypeId)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "编码已存在");
        }

    }

    private void saveMachTypeIcon(Integer machTypeId, List<SysMachTypeIconAddParam> icons, String code) {
        for (SysMachTypeIconAddParam param : icons) {
            if (MachTypeState.parseValue(param.getState()) == null) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "图标编码不存在");
            }
            if (StringUtils.isNotBlank(param.getIcon())) {
                SysMachTypeIcon typeIcon = new SysMachTypeIcon();
                typeIcon.setMachTypeId(machTypeId);
                typeIcon.setState(param.getState());
                typeIcon.setIconUrl(param.getIcon());
                sysMachTypeIconMapper.insertSelective(typeIcon);
            }
        }
    }

    private SysMachTypeDTO getParentSysMachType(Integer machTypeId) {
        SysMachTypeDTO sysMachType = sysMachTypeMapper.selectParentDTOByMachTypeId(machTypeId);
        getIcons(sysMachType);
        return sysMachType;
    }

    private SysMachTypeDTO getParentSysMachType(String code) {
        SysMachTypeDTO sysMachType = sysMachTypeMapper.selectParentDTOByCode(code);
        getIcons(sysMachType);
        return sysMachType;
    }

    private SysMachTypeDTO getSysMachType(Integer machTypeId) {
        SysMachType sysMachType = sysMachTypeMapper.selectById(machTypeId);
        SysMachTypeDTO sysMachTypeDTO = to(sysMachType);
        getIcons(sysMachTypeDTO);
        return sysMachTypeDTO;
    }

    private SysMachTypeDTO getSysMachType(String code) {
        SysMachType sysMachType = sysMachTypeMapper.selectByCode(code);
        SysMachTypeDTO sysMachTypeDTO = to(sysMachType);
        getIcons(sysMachTypeDTO);
        return sysMachTypeDTO;
    }

    private void getIcons(SysMachTypeDTO sysMachType) {
        if (sysMachType != null) {
            List<SysMachTypeIconDTO> sysMachTypeIconDTOS = sysMachTypeIconMapper.selectIconByMachTypeId(sysMachType.getMachTypeId());
            sysMachType.setIcons(sysMachTypeIconDTOS);
            machTypeRedisDao.setMachType(sysMachType);
        }
    }

    private SysMachTypeDTO to(SysMachType sysMachType) {
        if (sysMachType != null) {
            SysMachTypeDTO sysMachTypeDTO = new SysMachTypeDTO();
            BeanUtils.copyProperties(sysMachType, sysMachTypeDTO);
            sysMachTypeDTO.setMachTypeId(sysMachType.getId());
            return sysMachTypeDTO;
        }
        return null;
    }
}
